package org.ghost.springboot2.demo.util;

import com.fasterxml.jackson.core.type.TypeReference;
import org.ghost.springboot2.demo.common.function.Func;
import org.ghost.springboot2.demo.component.redis.RedisCacheUtil;

import java.util.List;
import java.util.Objects;

/**
 * Created by yarnliu on 2017-09-19.
 */
public final class CacheUtil {
    private CacheUtil() {
    }

    /**
     * 普通类型T
     *
     * @param redisCacheUtil
     * @param key
     * @param seconds
     * @param func
     * @param <T>
     * @return
     */
    public static <T> T getOrSet(RedisCacheUtil redisCacheUtil, String key, long seconds, Class<T> cls, Func<T> func) {
        T result = null;
        try {
            result = redisCacheUtil.get(key, cls);
        } catch (Exception e) {
            //
        }
        if (result == null) {
            if (func != null) {
                result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
            }
        }

        return result;
    }

    /**
     * 普通类型T
     *
     * @param redisCacheUtil
     * @param key
     * @param seconds
     * @param cls
     * @param func
     * @param useCache
     * @param <T>
     * @return
     */
    public static <T> T getOrSet(RedisCacheUtil redisCacheUtil, String key, long seconds, Class<T> cls, Func<T> func, boolean useCache) {
        if (useCache) {
            return getOrSet(redisCacheUtil, key, seconds, cls, func);
        } else {
            if (func != null) {
                T result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
                return result;
            }
        }

        return null;
    }

    public static <T> T getOrSet(RedisCacheUtil redisCacheUtil, String key, long seconds, TypeReference<T> typeReference, Func<T> func) {
        T result = null;
        try {
            result = redisCacheUtil.get(key, typeReference);
        } catch (Exception e) {
            //
        }
        if (result == null) {
            if (func != null) {
                result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
            }
        }

        return result;
    }

    public static <T> T getOrSet(RedisCacheUtil redisCacheUtil, String key, long seconds, TypeReference<T> typeReference, Func<T> func, boolean useCache) {
        if (useCache) {
            return getOrSet(redisCacheUtil, key, seconds, typeReference, func);
        } else {
            if (func != null) {
                T result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
                return result;
            }
        }

        return null;
    }

    /**
     * 获取设置List<T>数据
     *
     * @param redisCacheUtil
     * @param key            缓存key
     * @param seconds        缓存秒数
     * @param cls            目标类型
     * @param func           取值
     * @param <T>
     * @return
     */
    public static <T> List<T> getOrSetList(RedisCacheUtil redisCacheUtil, String key, long seconds, Class<T> cls, Func<List<T>> func) {
        List<T> result = null;
        try {
            //封测与正式类名不一样导致序列化报错
            result = redisCacheUtil.getList(key, cls);
            if (result != null && !result.isEmpty()) {
                if (!Objects.equals(result.get(0).getClass(), cls)) {
                    result = null;
                }
            }
        } catch (Exception e) {
            //
        }
        if (result == null || result.isEmpty()) {
            if (func != null) {
                result = func.execute();
                if (result != null && !result.isEmpty()) {
                    redisCacheUtil.set(key, result, seconds);
                }
            }
        }

        return result;
    }

    public static <T> List<T> getOrSetList(RedisCacheUtil redisCacheUtil, String key, long seconds, Class<T> cls, Func<List<T>> func, boolean useCache) {
        if (useCache) {
            return getOrSetList(redisCacheUtil, key, seconds, cls, func);
        } else {
            if (func != null) {
                List<T> result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
                return result;
            }
        }

        return null;
    }

    /**
     * 获取设置List<T>数据
     *
     * @param redisCacheUtil
     * @param key            缓存key
     * @param seconds        缓存秒数
     * @param typeReference  目标类型
     * @param func           取值
     * @param <T>
     * @return
     */
    public static <T> List<T> getOrSetList(RedisCacheUtil redisCacheUtil, String key, long seconds, TypeReference<T> typeReference, Func<List<T>> func) {
        List<T> result = null;
        try {
            //封测与正式类名不一样导致序列化报错
            result = redisCacheUtil.getList(key, typeReference);
            if (result != null && !result.isEmpty()) {
                if (!Objects.equals(result.get(0).getClass(), typeReference)) {
                    result = null;
                }
            }
        } catch (Exception e) {
            //
        }
        if (result == null || result.isEmpty()) {
            if (func != null) {
                result = func.execute();
                if (result != null && !result.isEmpty()) {
                    redisCacheUtil.set(key, result, seconds);
                }
            }
        }

        return result;
    }

    public static <T> List<T> getOrSetList(RedisCacheUtil redisCacheUtil, String key, long seconds, TypeReference<T> typeReference, Func<List<T>> func, boolean useCache) {
        if (useCache) {
            return getOrSetList(redisCacheUtil, key, seconds, typeReference, func);
        } else {
            if (func != null) {
                List<T> result = func.execute();
                if (result != null) {
                    redisCacheUtil.set(key, result, seconds);
                }
                return result;
            }
        }

        return null;
    }


}
